<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>数学坐标系Canvas画布</title>
    <style>
        body {
            margin: 0;
            overflow: hidden;
            font-family: Arial, sans-serif;
        }

        #canvas-container {
            position: relative;
            width: 100vw;
            height: 100vh;
            overflow: hidden;
        }

        canvas {
            display: block;
            background-color: #f5f5f5;
            cursor: crosshair;
        }

        #controls {
            position: absolute;
            top: 10px;
            left: 10px;
            background: rgba(255, 255, 255, 0.9);
            padding: 10px;
            border-radius: 5px;
            box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
            display: flex;
            flex-direction: column;
            gap: 5px;
            z-index: 10;
            -webkit-user-select: none;
            user-select: none;
        }

        #controls:hover {
            -webkit-user-select: auto;
            user-select: auto;
        }

        #property-panel {
            position: absolute;
            top: 10px;
            right: 10px;
            background: rgba(255, 255, 255, 0.9);
            padding: 10px;
            border-radius: 5px;
            box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
            width: 250px;
            max-height: 80vh;
            overflow-y: auto;
            z-index: 10;
            -webkit-user-select: none;
            user-select: none;
        }

        #property-panel:hover {
            -webkit-user-select: auto;
            user-select: auto;
        }

        .control-group {
            display: flex;
            align-items: center;
            gap: 5px;
        }

        button {
            margin: 0 5px;
            padding: 5px 10px;
        }

        .active {
            background-color: #4CAF50;
            color: white;
        }

        .mode-group {
            display: inline-block;
            margin-right: 10px;
        }

        input[type="color"],
        input[type="range"],
        input[type="number"],
        input[type="text"] {
            vertical-align: middle;
        }

        label {
            font-size: 14px;
            white-space: nowrap;
        }

        .property-item {
            margin-bottom: 8px;
        }

        .property-title {
            font-weight: bold;
            margin-bottom: 5px;
            border-bottom: 1px solid #ddd;
            padding-bottom: 3px;
        }

        .property-row {
            display: flex;
            justify-content: space-between;
            margin-bottom: 3px;
            align-items: center;
        }

        .property-label {
            font-weight: bold;
            color: #555;
        }

        .property-value {
            text-align: right;
        }

        .point-list {
            max-height: 150px;
            overflow-y: auto;
            border: 1px solid #ddd;
            padding: 5px;
            margin-top: 5px;
            background: #f9f9f9;
            border-radius: 3px;
        }

        .point-item {
            font-family: monospace;
            font-size: 12px;
            margin-bottom: 2px;
        }

        .edit-input {
            width: 70px;
            padding: 2px;
            text-align: right;
        }

        .action-button {
            margin-top: 5px;
            padding: 5px;
            width: 100%;
        }

        .anchor-point {
            position: absolute;
            width: 10px;
            height: 10px;
            background-color: red;
            border-radius: 50%;
            transform: translate(-50%, -50%);
            cursor: move;
            z-index: 20;
            border: 2px solid white;
            box-sizing: border-box;
        }

        .anchor-point:hover {
            background-color: #ff6b6b;
            transform: translate(-50%, -50%) scale(1.2);
        }
    </style>
</head>

<body>
    <div id="canvas-container">
        <canvas id="canvas"></canvas>
        <div id="controls">
            <div class="control-group">
                <div class="mode-group">
                    <button id="select-mode">选择</button>
                    <button id="draw-mode">绘制</button>
                    <button id="rect-mode">矩形</button>
                    <button id="circle-mode">圆形</button>
                </div>
            </div>
            <div class="control-group">
                <label for="stroke-color">颜色:</label>
                <input type="color" id="stroke-color" value="#0000ff">
                <label for="stroke-width">粗细:</label>
                <input type="range" id="stroke-width" min="1" max="20" value="2">
            </div>
            <div class="control-group">
                <button id="reset-view" class="action-button">回到原点</button>
                <button id="clear-canvas" class="action-button">清空画布</button>
            </div>
            <span id="position-info">X: 0, Y: 0</span>
        </div>
        <div id="property-panel">
            <div class="property-title">属性面板</div>
            <div id="shape-properties">
                <div class="no-selection">未选中任何形状</div>
            </div>
        </div>
        <div id="anchor-points-container"></div>
    </div>

    <script>
        const canvas = document.getElementById('canvas');
        const ctx = canvas.getContext('2d');
        const selectModeBtn = document.getElementById('select-mode');
        const drawModeBtn = document.getElementById('draw-mode');
        const rectModeBtn = document.getElementById('rect-mode');
        const circleModeBtn = document.getElementById('circle-mode');
        const strokeColorInput = document.getElementById('stroke-color');
        const strokeWidthInput = document.getElementById('stroke-width');
        const positionInfo = document.getElementById('position-info');
        const shapePropertiesPanel = document.getElementById('shape-properties');
        const resetViewBtn = document.getElementById('reset-view');
        const clearCanvasBtn = document.getElementById('clear-canvas');
        const anchorPointsContainer = document.getElementById('anchor-points-container');

        // 形状基类
        class Shape {
            constructor(x, y, color = 'blue', lineWidth = 2) {
                this.x = x;
                this.y = y;
                this.color = color;
                this.lineWidth = lineWidth;
                this.selected = false;
            }

            draw(ctx) {
                throw new Error('Method "draw" must be implemented');
            }

            updateEnd(x, y) {
                throw new Error('Method "updateEnd" must be implemented');
            }

            contains(x, y) {
                throw new Error('Method "contains" must be implemented');
            }

            getProperties() {
                return {
                    type: 'Shape',
                    color: this.color,
                    lineWidth: this.lineWidth,
                    position: { x: this.x.toFixed(1), y: this.y.toFixed(1) }
                };
            }

            drawSelection(ctx) {
                const bounds = this.getBounds();
                if (!bounds) return;

                ctx.save();
                ctx.strokeStyle = 'red';
                ctx.lineWidth = 2 / state.scale;
                ctx.setLineDash([5 / state.scale, 5 / state.scale]);
                ctx.beginPath();
                ctx.rect(bounds.left, -bounds.top, bounds.right - bounds.left, -(bounds.bottom - bounds.top));
                ctx.stroke();
                ctx.restore();
            }

            getBounds() {
                return null;
            }

            updateProperty(prop, value) {
                if (prop === 'color') {
                    this.color = value;
                } else if (prop === 'lineWidth') {
                    this.lineWidth = parseInt(value);
                }
            }
        }

        // 矩形类
        class Rectangle extends Shape {
            constructor(x, y, color, lineWidth) {
                super(x, y, color, lineWidth);
                this.endX = x;
                this.endY = y;
                this.anchors = [];
            }

            draw(ctx) {
                ctx.strokeStyle = this.color;
                ctx.lineWidth = this.lineWidth / state.scale;
                ctx.beginPath();

                const left = Math.min(this.x, this.endX);
                const right = Math.max(this.x, this.endX);
                const top = Math.min(this.y, this.endY);
                const bottom = Math.max(this.y, this.endY);

                ctx.rect(left, -top, right - left, -(bottom - top));
                ctx.stroke();

                if (this.selected) {
                    this.drawSelection(ctx);
                }
            }

            updateEnd(x, y) {
                this.endX = x;
                this.endY = y;
            }

            contains(x, y) {
                const left = Math.min(this.x, this.endX);
                const right = Math.max(this.x, this.endX);
                const top = Math.max(this.y, this.endY);
                const bottom = Math.min(this.y, this.endY);

                // 注意：y是已经翻转过的坐标（屏幕坐标，向下为正）
                // 所以需要与top/bottom比较时取反
                return x >= left && x <= right &&
                    y >= bottom && y <= top;  // 修正后的Y轴判断
            }

            getProperties() {
                const left = Math.min(this.x, this.endX);
                const right = Math.max(this.x, this.endX);
                const top = Math.min(this.y, this.endY);
                const bottom = Math.max(this.y, this.endY);
                const width = right - left;
                const height = bottom - top;
                const centerX = (left + right) / 2;
                const centerY = (top + bottom) / 2;

                return {
                    type: 'Rectangle',
                    color: this.color,
                    lineWidth: this.lineWidth,
                    position: { x: this.x.toFixed(1), y: this.y.toFixed(1) },
                    endPosition: { x: this.endX.toFixed(1), y: this.endY.toFixed(1) },
                    dimensions: {
                        width: width.toFixed(1),
                        height: height.toFixed(1)
                    },
                    center: {
                        x: centerX.toFixed(1),
                        y: centerY.toFixed(1)
                    },
                    area: (width * height).toFixed(1)
                };
            }

            getBounds() {
                return {
                    left: Math.min(this.x, this.endX),
                    right: Math.max(this.x, this.endX),
                    top: Math.max(this.y, this.endY),
                    bottom: Math.min(this.y, this.endY)
                };
            }

            updateProperty(prop, value) {
                super.updateProperty(prop, value);
                if (prop === 'x') {
                    this.x = parseFloat(value);
                } else if (prop === 'y') {
                    this.y = parseFloat(value);
                } else if (prop === 'endX') {
                    this.endX = parseFloat(value);
                } else if (prop === 'endY') {
                    this.endY = parseFloat(value);
                }
            }

            createAnchors() {
                const bounds = this.getBounds();
                if (!bounds) return;

                this.anchors = [
                    { x: bounds.left, y: bounds.top, type: 'nw' },
                    { x: bounds.right, y: bounds.top, type: 'ne' },
                    { x: bounds.right, y: bounds.bottom, type: 'se' },
                    { x: bounds.left, y: bounds.bottom, type: 'sw' },
                    { x: (bounds.left + bounds.right) / 2, y: bounds.top, type: 'n' },
                    { x: bounds.right, y: (bounds.top + bounds.bottom) / 2, type: 'e' },
                    { x: (bounds.left + bounds.right) / 2, y: bounds.bottom, type: 's' },
                    { x: bounds.left, y: (bounds.top + bounds.bottom) / 2, type: 'w' }
                ];
            }
        }

        // 圆形类
        class Circle extends Shape {
            constructor(x, y, color, lineWidth) {
                super(x, y, color, lineWidth);
                this.radius = 0;
                this.anchors = [];
            }

            draw(ctx) {
                ctx.strokeStyle = this.color;
                ctx.lineWidth = this.lineWidth / state.scale;
                ctx.beginPath();
                ctx.arc(this.x, -this.y, this.radius, 0, Math.PI * 2);
                ctx.stroke();

                if (this.selected) {
                    this.drawSelection(ctx);
                }
            }

            updateEnd(x, y) {
                const dx = x - this.x;
                const dy = y - this.y;
                this.radius = Math.sqrt(dx * dx + dy * dy);
            }

            contains(x, y) {
                // 注意：this.y是数学坐标（向上为正），而y是屏幕坐标（向下为正）
                const dx = x - this.x;
                const dy = y - this.y;  // 将数学坐标的y转换为屏幕坐标
                const distance = Math.sqrt(dx * dx + dy * dy);
                return distance <= this.radius + (5 / state.scale);
            }

            getProperties() {
                return {
                    type: 'Circle',
                    color: this.color,
                    lineWidth: this.lineWidth,
                    center: { x: this.x.toFixed(1), y: this.y.toFixed(1) },
                    radius: this.radius.toFixed(1),
                    diameter: (this.radius * 2).toFixed(1),
                    circumference: (2 * Math.PI * this.radius).toFixed(1),
                    area: (Math.PI * this.radius * this.radius).toFixed(1)
                };
            }

            getBounds() {
                return {
                    left: this.x - this.radius,
                    right: this.x + this.radius,
                    top: this.y + this.radius,
                    bottom: this.y - this.radius
                };
            }

            updateProperty(prop, value) {
                super.updateProperty(prop, value);
                if (prop === 'x') {
                    this.x = parseFloat(value);
                } else if (prop === 'y') {
                    this.y = parseFloat(value);
                } else if (prop === 'radius') {
                    this.radius = parseFloat(value);
                }
            }

            createAnchors() {
                this.anchors = [
                    { x: this.x, y: this.y - this.radius, type: 'n' },
                    { x: this.x + this.radius, y: this.y, type: 'e' },
                    { x: this.x, y: this.y + this.radius, type: 's' },
                    { x: this.x - this.radius, y: this.y, type: 'w' }
                ];
            }
        }

        // 路径类
        class Path extends Shape {
            constructor(x, y, color, lineWidth) {
                super(x, y, color, lineWidth);
                this.points = [{ x, y }];
                this.anchors = [];
            }

            addPoint(x, y) {
                this.points.push({ x, y });
            }

            updateEnd(x, y) {
                this.addPoint(x, y);
            }

            draw(ctx) {
                ctx.strokeStyle = this.color;
                ctx.lineWidth = this.lineWidth / state.scale;
                ctx.beginPath();

                const firstPoint = this.points[0];
                ctx.moveTo(firstPoint.x, -firstPoint.y);

                for (let i = 1; i < this.points.length; i++) {
                    const point = this.points[i];
                    ctx.lineTo(point.x, -point.y);
                }

                ctx.stroke();

                if (this.selected) {
                    this.drawSelection(ctx);
                }
            }

            contains(x, y) {
                const hitDistance = (10 + this.lineWidth) / state.scale;

                for (let i = 0; i < this.points.length - 1; i++) {
                    const p1 = this.points[i];
                    const p2 = this.points[i + 1];

                    // 注意：p1.y和p2.y是数学坐标，需要转换为屏幕坐标
                    const distance = this.pointToLineDistance(
                        x, y,
                        p1.x, p1.y,  // 转换为屏幕坐标
                        p2.x, p2.y   // 转换为屏幕坐标
                    );
                    if (distance <= hitDistance) {
                        return true;
                    }
                }

                const firstPoint = this.points[0];
                const lastPoint = this.points[this.points.length - 1];
                const dx1 = x - firstPoint.x;
                const dy1 = y - firstPoint.y;  // 转换为屏幕坐标
                const dx2 = x - lastPoint.x;
                const dy2 = y - lastPoint.y;    // 转换为屏幕坐标
                const dist1 = Math.sqrt(dx1 * dx1 + dy1 * dy1);
                const dist2 = Math.sqrt(dx2 * dx2 + dy2 * dy2);

                return dist1 <= hitDistance || dist2 <= hitDistance;
            }

            pointToLineDistance(px, py, x1, y1, x2, y2) {
                // 注意：这里所有y坐标都已经是屏幕坐标（向下为正）
                const A = px - x1;
                const B = py - y1;
                const C = x2 - x1;
                const D = y2 - y1;

                const dot = A * C + B * D;
                const len_sq = C * C + D * D;
                let param = -1;
                if (len_sq !== 0) param = dot / len_sq;

                let xx, yy;

                if (param < 0) {
                    xx = x1;
                    yy = y1;
                } else if (param > 1) {
                    xx = x2;
                    yy = y2;
                } else {
                    xx = x1 + param * C;
                    yy = y1 + param * D;
                }

                const dx = px - xx;
                const dy = py - yy;
                return Math.sqrt(dx * dx + dy * dy);
            }

            getProperties() {
                let length = 0;
                for (let i = 0; i < this.points.length - 1; i++) {
                    const p1 = this.points[i];
                    const p2 = this.points[i + 1];
                    const dx = p2.x - p1.x;
                    const dy = p2.y - p1.y;
                    length += Math.sqrt(dx * dx + dy * dy);
                }

                return {
                    type: 'Path',
                    color: this.color,
                    lineWidth: this.lineWidth,
                    startPoint: { x: this.points[0].x.toFixed(1), y: this.points[0].y.toFixed(1) },
                    endPoint: {
                        x: this.points[this.points.length - 1].x.toFixed(1),
                        y: this.points[this.points.length - 1].y.toFixed(1)
                    },
                    pointCount: this.points.length,
                    pathLength: length.toFixed(1),
                    points: this.points.map(p => ({ x: p.x.toFixed(1), y: p.y.toFixed(1) }))
                };
            }

            getBounds() {
                if (this.points.length === 0) return null;

                let left = this.points[0].x;
                let right = this.points[0].x;
                let top = this.points[0].y;
                let bottom = this.points[0].y;

                for (const point of this.points) {
                    left = Math.min(left, point.x);
                    right = Math.max(right, point.x);
                    top = Math.max(top, point.y);
                    bottom = Math.min(bottom, point.y);
                }

                return { left, right, top, bottom };
            }

            updateProperty(prop, value) {
                super.updateProperty(prop, value);
                if (prop.startsWith('point-')) {
                    const index = parseInt(prop.split('-')[1]);
                    const coord = prop.split('-')[2];
                    if (coord === 'x') {
                        this.points[index].x = parseFloat(value);
                    } else if (coord === 'y') {
                        this.points[index].y = parseFloat(value);
                    }
                }
            }

            createAnchors() {
                const bounds = this.getBounds();
                if (!bounds || this.points.length === 0) return;

                this.anchors = [
                    { x: bounds.left, y: bounds.top, type: 'nw' },
                    { x: bounds.right, y: bounds.top, type: 'ne' },
                    { x: bounds.right, y: bounds.bottom, type: 'se' },
                    { x: bounds.left, y: bounds.bottom, type: 'sw' }
                ];
            }
        }

        // 画布状态
        const state = {
            mode: 'select',
            isDragging: false,
            isDrawing: false,
            isSelecting: false,
            isMovingShape: false,
            isResizing: false,
            dragStartX: 0,
            dragStartY: 0,
            offsetX: 0,
            offsetY: 0,
            scale: 1,
            lastX: 0,
            lastY: 0,
            originX: 0,
            originY: 0,
            currentShape: null,
            shapes: [],
            selectedShape: null,
            strokeColor: '#0000ff',
            strokeWidth: 2,
            activeAnchor: null
        };

        // 更新属性面板
        function updatePropertyPanel() {
            if (!state.selectedShape) {
                shapePropertiesPanel.innerHTML = '<div class="no-selection">未选中任何形状</div>';
                return;
            }

            const props = state.selectedShape.getProperties();
            let html = `<div class="property-title">${props.type} 属性</div>`;

            // 通用属性
            html += `
                <div class="property-item">
                    <div class="property-row">
                        <span class="property-label">颜色:</span>
                        <input type="color" value="${props.color}" 
                               onchange="updateShapeProperty('color', this.value)" class="property-value">
                    </div>
                    <div class="property-row">
                        <span class="property-label">线宽:</span>
                        <input type="number" value="${props.lineWidth}" min="1" max="20" 
                               onchange="updateShapeProperty('lineWidth', this.value)" class="property-value edit-input">
                    </div>
                </div>
            `;

            // 特定形状属性
            if (props.type === 'Rectangle') {
                html += `
                    <div class="property-item">
                        <div class="property-row">
                            <span class="property-label">起点X:</span>
                            <input type="number" value="${props.position.x}" 
                                   onchange="updateShapeProperty('x', this.value)" class="property-value edit-input">
                        </div>
                        <div class="property-row">
                            <span class="property-label">起点Y:</span>
                            <input type="number" value="${props.position.y}" 
                                   onchange="updateShapeProperty('y', this.value)" class="property-value edit-input">
                        </div>
                        <div class="property-row">
                            <span class="property-label">终点X:</span>
                            <input type="number" value="${props.endPosition.x}" 
                                   onchange="updateShapeProperty('endX', this.value)" class="property-value edit-input">
                        </div>
                        <div class="property-row">
                            <span class="property-label">终点Y:</span>
                            <input type="number" value="${props.endPosition.y}" 
                                   onchange="updateShapeProperty('endY', this.value)" class="property-value edit-input">
                        </div>
                        <div class="property-row">
                            <span class="property-label">宽度:</span>
                            <span class="property-value">${props.dimensions.width}</span>
                        </div>
                        <div class="property-row">
                            <span class="property-label">高度:</span>
                            <span class="property-value">${props.dimensions.height}</span>
                        </div>
                        <div class="property-row">
                            <span class="property-label">面积:</span>
                            <span class="property-value">${props.area}</span>
                        </div>
                    </div>
                `;
            } else if (props.type === 'Circle') {
                html += `
                    <div class="property-item">
                        <div class="property-row">
                            <span class="property-label">圆心X:</span>
                            <input type="number" value="${props.center.x}" 
                                   onchange="updateShapeProperty('x', this.value)" class="property-value edit-input">
                        </div>
                        <div class="property-row">
                            <span class="property-label">圆心Y:</span>
                            <input type="number" value="${props.center.y}" 
                                   onchange="updateShapeProperty('y', this.value)" class="property-value edit-input">
                        </div>
                        <div class="property-row">
                            <span class="property-label">半径:</span>
                            <input type="number" value="${props.radius}" 
                                   onchange="updateShapeProperty('radius', this.value)" class="property-value edit-input">
                        </div>
                        <div class="property-row">
                            <span class="property-label">直径:</span>
                            <span class="property-value">${props.diameter}</span>
                        </div>
                        <div class="property-row">
                            <span class="property-label">周长:</span>
                            <span class="property-value">${props.circumference}</span>
                        </div>
                        <div class="property-row">
                            <span class="property-label">面积:</span>
                            <span class="property-value">${props.area}</span>
                        </div>
                    </div>
                `;
            } else if (props.type === 'Path') {
                html += `
                    <div class="property-item">
                        <div class="property-row">
                            <span class="property-label">点数:</span>
                            <span class="property-value">${props.pointCount}</span>
                        </div>
                        <div class="property-row">
                            <span class="property-label">长度:</span>
                            <span class="property-value">${props.pathLength}</span>
                        </div>
                        <div class="property-row">
                            <span class="property-label">路径点:</span>
                        </div>
                        <div class="point-list">
                            ${props.points.map((p, i) => `
                                <div class="point-item">
                                    ${i + 1}. X: <input type="number" value="${p.x}" 
                                        onchange="updateShapeProperty('point-${i}-x', this.value)" class="edit-input">
                                    Y: <input type="number" value="${p.y}" 
                                        onchange="updateShapeProperty('point-${i}-y', this.value)" class="edit-input">
                                </div>
                            `).join('')}
                        </div>
                    </div>
                `;
            }

            shapePropertiesPanel.innerHTML = html;
        }

        // 更新形状属性
        function updateShapeProperty(prop, value) {
            if (state.selectedShape) {
                state.selectedShape.updateProperty(prop, value);
                if (state.selectedShape.createAnchors) {
                    state.selectedShape.createAnchors();
                }
                updateAnchors();
                updatePropertyPanel();
                draw();
            }
        }

        // 创建锚点
        function createAnchors() {
            clearAnchors();
            if (!state.selectedShape || !state.selectedShape.createAnchors) return;

            state.selectedShape.createAnchors();
            state.selectedShape.anchors.forEach(anchor => {
                const anchorElement = document.createElement('div');
                anchorElement.className = 'anchor-point';
                anchorElement.dataset.type = anchor.type;

                const screenPos = worldToScreen(anchor.x, anchor.y);
                anchorElement.style.left = `${screenPos.x}px`;
                anchorElement.style.top = `${screenPos.y}px`;

                anchorElement.addEventListener('mousedown', (e) => {
                    e.stopPropagation();
                    e.preventDefault();
                    state.isResizing = true;
                    state.activeAnchor = anchor.type;
                    const worldPos = screenToWorld(e.clientX, e.clientY);
                    state.dragStartX = worldPos.x;
                    state.dragStartY = worldPos.y;
                    document.addEventListener('mousemove', handleAnchorMove);
                    document.addEventListener('mouseup', handleAnchorUp);
                });

                anchorPointsContainer.appendChild(anchorElement);
            });
        }

        // 处理锚点移动
        function handleAnchorMove(e) {
            if (!state.isResizing || !state.selectedShape) return;

            const worldPos = screenToWorld(e.clientX, e.clientY);

            handleShapeResize(worldPos.x, worldPos.y);
        }

        // 处理锚点释放
        function handleAnchorUp() {
            state.isResizing = false;
            state.activeAnchor = null;
            document.removeEventListener('mousemove', handleAnchorMove);
            document.removeEventListener('mouseup', handleAnchorUp);
            console.log("handleAnchorUp");
        }

        // 清除锚点
        function clearAnchors() {
            anchorPointsContainer.innerHTML = '';
        }

        // 更新锚点位置
        function updateAnchors() {
            if (!state.selectedShape || !state.selectedShape.anchors) return;

            const anchors = document.querySelectorAll('.anchor-point');
            anchors.forEach((anchor, index) => {
                const anchorData = state.selectedShape.anchors[index];
                if (anchorData) {
                    const screenPos = worldToScreen(anchorData.x, anchorData.y);
                    anchor.style.left = `${screenPos.x}px`;
                    anchor.style.top = `${screenPos.y}px`;
                }
            });
        }

        // 世界坐标转屏幕坐标（处理Y轴翻转）
        function worldToScreen(x, y) {
            return {
                x: x * state.scale + state.offsetX,
                y: -y * state.scale + state.offsetY  // 这里翻转Y轴
            };
        }

        // 屏幕坐标转世界坐标（处理Y轴翻转）
        function screenToWorld(x, y) {
            return {
                x: (x - state.offsetX) / state.scale,
                y: -(y - state.offsetY) / state.scale  // 这里翻转Y轴
            };
        }

        // 设置canvas大小为窗口大小
        function resizeCanvas() {
            canvas.width = window.innerWidth;
            canvas.height = window.innerHeight;
            state.offsetX = canvas.width / 2;
            state.offsetY = canvas.height / 2;
            draw();
        }

        // 绘制所有形状
        function drawShapes() {
            state.shapes.forEach(shape => {
                shape.draw(ctx);
                if (shape.selected) {
                    shape.drawSelection(ctx);
                }
            });
        }

        // 绘制坐标系
        function drawCoordinateSystem() {
            const width = canvas.width;
            const height = canvas.height;
            const scaledWidth = width / state.scale;
            const scaledHeight = height / state.scale;

            const left = -state.offsetX / state.scale;
            const top = state.offsetY / state.scale;
            const right = left + scaledWidth;
            const bottom = top - scaledHeight;

            ctx.strokeStyle = '#ccc';
            ctx.lineWidth = 1 / state.scale;

            const gridSize = 50;
            const startX = Math.floor(left / gridSize) * gridSize;
            const startY = Math.ceil(top / gridSize) * gridSize;

            for (let x = startX; x < right; x += gridSize) {
                ctx.beginPath();
                ctx.moveTo(x, -top);
                ctx.lineTo(x, -bottom);
                ctx.stroke();
            }

            for (let y = startY; y > bottom; y -= gridSize) {
                ctx.beginPath();
                ctx.moveTo(left, -y);
                ctx.lineTo(right, -y);
                ctx.stroke();
            }

            ctx.strokeStyle = '#000';
            ctx.lineWidth = 2 / state.scale;
            ctx.beginPath();
            ctx.moveTo(left, 0);
            ctx.lineTo(right, 0);
            ctx.stroke();
            ctx.beginPath();
            ctx.moveTo(0, -top);
            ctx.lineTo(0, -bottom);
            ctx.stroke();
        }

        // 绘制原点标记
        function drawOrigin() {
            ctx.fillStyle = 'red';
            ctx.beginPath();
            ctx.arc(0, 0, 5 / state.scale, 0, Math.PI * 2);
            ctx.fill();
            ctx.font = `${12 / state.scale}px Arial`;
            ctx.fillStyle = 'red';
            ctx.fillText('(0,0)', 10 / state.scale, -10 / state.scale);
        }

        // 绘制函数
        function draw() {
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            ctx.save();
            ctx.translate(state.offsetX, state.offsetY);
            ctx.scale(state.scale, state.scale); // 保持Y轴不翻转

            drawCoordinateSystem();
            drawOrigin();
            drawShapes();

            if (state.currentShape) {
                state.currentShape.draw(ctx);
            }

            ctx.restore();
            updatePositionInfo();
            updateAnchors();
        }

        // 更新位置信息显示
        function updatePositionInfo() {
            const worldPos = screenToWorld(state.lastX, state.lastY);
            positionInfo.textContent = `X: ${worldPos.x.toFixed(1)}, Y: ${worldPos.y.toFixed(1)}`;
        }

        // 检查点是否在任何形状内
        function isPointInAnyShape(x, y) {
            for (let i = state.shapes.length - 1; i >= 0; i--) {
                if (state.shapes[i].contains(x, y)) {
                    return true;
                }
            }
            return false;
        }

        // 选择形状
        function selectShape(x, y) {
            if (state.selectedShape) {
                state.selectedShape.selected = false;
                state.selectedShape = null;
                clearAnchors();
            }

            for (let i = state.shapes.length - 1; i >= 0; i--) {
                const shape = state.shapes[i];
                if (shape.contains(x, y)) {
                    shape.selected = true;
                    state.selectedShape = shape;
                    createAnchors();
                    break;
                }
            }

            updatePropertyPanel();
            draw();
        }

        // 创建新形状
        function createShape(x, y) {
            const color = state.strokeColor;
            const lineWidth = state.strokeWidth;

            switch (state.mode) {
                case 'draw': return new Path(x, y, color, lineWidth);
                case 'rect': return new Rectangle(x, y, color, lineWidth);
                case 'circle': return new Circle(x, y, color, lineWidth);
                default: return null;
            }
        }

        // 处理形状调整大小
        function handleShapeResize(worldX, worldY) {
            if (!state.selectedShape || !state.activeAnchor) return;

            const dx = worldX - state.dragStartX;
            const dy = worldY - state.dragStartY;

            if (state.selectedShape instanceof Rectangle) {
                const bounds = state.selectedShape.getBounds();
                const width = bounds.right - bounds.left;
                const height = bounds.bottom - bounds.top;

                switch (state.activeAnchor) {
                    case 'nw':
                        state.selectedShape.x += dx;
                        state.selectedShape.y += dy;
                        break;
                    case 'ne':
                        state.selectedShape.endX += dx;
                        state.selectedShape.y += dy;
                        break;
                    case 'se':
                        state.selectedShape.endX += dx;
                        state.selectedShape.endY += dy;
                        break;
                    case 'sw':
                        state.selectedShape.x += dx;
                        state.selectedShape.endY += dy;
                        break;
                    case 'n':
                        state.selectedShape.y += dy;
                        break;
                    case 'e':
                        state.selectedShape.endX += dx;
                        break;
                    case 's':
                        state.selectedShape.endY += dy;
                        break;
                    case 'w':
                        state.selectedShape.x += dx;
                        break;
                }
            }
            else if (state.selectedShape instanceof Circle) {
                const dxTotal = worldX - state.selectedShape.x;
                const dyTotal = worldY - state.selectedShape.y;

                switch (state.activeAnchor) {
                    case 'n':
                        state.selectedShape.radius = Math.abs(state.selectedShape.y - worldY);
                        break;
                    case 'e':
                        state.selectedShape.radius = Math.abs(worldX - state.selectedShape.x);
                        break;
                    case 's':
                        state.selectedShape.radius = Math.abs(worldY - state.selectedShape.y);
                        break;
                    case 'w':
                        state.selectedShape.radius = Math.abs(state.selectedShape.x - worldX);
                        break;
                }
            }
            else if (state.selectedShape instanceof Path) {
                // 路径的调整大小改为等比缩放
                const bounds = state.selectedShape.getBounds();
                const centerX = (bounds.left + bounds.right) / 2;
                const centerY = (bounds.top + bounds.bottom) / 2;

                let scaleX = 1, scaleY = 1;

                switch (state.activeAnchor) {
                    case 'nw':
                        scaleX = (centerX - worldX) / (centerX - bounds.left);
                        scaleY = (centerY - worldY) / (centerY - bounds.top);
                        break;
                    case 'ne':
                        scaleX = (worldX - centerX) / (bounds.right - centerX);
                        scaleY = (centerY - worldY) / (centerY - bounds.top);
                        break;
                    case 'se':
                        scaleX = (worldX - centerX) / (bounds.right - centerX);
                        scaleY = (worldY - centerY) / (bounds.bottom - centerY);
                        break;
                    case 'sw':
                        scaleX = (centerX - worldX) / (centerX - bounds.left);
                        scaleY = (worldY - centerY) / (bounds.bottom - centerY);
                        break;
                }

                // 保持等比缩放
                const scale = Math.max(scaleX, scaleY);

                state.selectedShape.points.forEach(point => {
                    point.x = centerX + (point.x - centerX) * scale;
                    point.y = centerY + (point.y - centerY) * scale;
                });
            }

            state.dragStartX = worldX;
            state.dragStartY = worldY;
            state.selectedShape.createAnchors();
            updatePropertyPanel();
            draw();
        }

        // 鼠标事件处理
        canvas.addEventListener('mousedown', (e) => {
            const worldPos = screenToWorld(e.clientX, e.clientY);
            const worldX = worldPos.x;
            const worldY = worldPos.y;

            state.lastX = e.clientX;
            state.lastY = e.clientY;

            switch (state.mode) {
                case 'select':
                    if (state.selectedShape && state.selectedShape.contains(worldX, worldY)) {
                        state.isMovingShape = true;
                        state.dragStartX = worldX;
                        state.dragStartY = worldY;
                        canvas.style.cursor = 'move';
                    } else if (isPointInAnyShape(worldX, worldY)) {
                        selectShape(worldX, worldY);
                        state.isSelecting = true;
                    } else {
                        state.isDragging = true;
                        canvas.style.cursor = 'grabbing';
                    }
                    break;

                case 'draw':
                case 'rect':
                case 'circle':
                    state.currentShape = createShape(worldX, worldY);
                    state.isDrawing = true;
                    break;
            }
        });

        canvas.addEventListener('mousemove', (e) => {
            const currentX = e.clientX;
            const currentY = e.clientY;
            const worldPos = screenToWorld(currentX, currentY);
            const worldX = worldPos.x;
            const worldY = worldPos.y;

            if (state.isDrawing && state.currentShape) {
                state.currentShape.updateEnd(worldX, worldY);
                draw();
            }
            else if (state.isMovingShape && state.selectedShape) {
                const dx = worldX - state.dragStartX;
                const dy = worldY - state.dragStartY;

                if (state.selectedShape instanceof Path) {
                    state.selectedShape.points.forEach(point => {
                        point.x += dx;
                        point.y += dy;
                    });
                } else if (state.selectedShape instanceof Circle) {
                    state.selectedShape.x += dx;
                    state.selectedShape.y += dy;
                } else {
                    state.selectedShape.x += dx;
                    state.selectedShape.y += dy;
                    if (state.selectedShape.endX !== undefined) {
                        state.selectedShape.endX += dx;
                        state.selectedShape.endY += dy;
                    }
                }

                state.dragStartX = worldX;
                state.dragStartY = worldY;
                state.selectedShape.createAnchors();
                updatePropertyPanel();
                draw();
            }
            else if (state.isDragging) {
                const dx = currentX - state.lastX;
                const dy = currentY - state.lastY;

                state.offsetX += dx;
                state.offsetY += dy;
                draw();
            }

            state.lastX = currentX;
            state.lastY = currentY;
            updatePositionInfo();
        });

        canvas.addEventListener('mouseup', () => {
            if (state.isDrawing && state.currentShape) {
                state.shapes.push(state.currentShape);
                state.currentShape = null;
                state.isDrawing = false;
            }
            else if (state.isMovingShape) {
                state.isMovingShape = false;
                canvas.style.cursor = 'default';
            }
            else if (state.isResizing) {
                state.isResizing = false;
                state.activeAnchor = null;
                canvas.style.cursor = 'default';
            }
            else if (state.isDragging) {
                state.isDragging = false;
                canvas.style.cursor = 'default';
            }
            else if (state.isSelecting) {
                state.isSelecting = false;
            }
        });

        canvas.addEventListener('mouseleave', () => {
            if (state.isDrawing && state.currentShape) {
                state.shapes.push(state.currentShape);
                state.currentShape = null;
                state.isDrawing = false;
            } else if (state.isDragging) {
                state.isDragging = false;
                canvas.style.cursor = 'default';
            } else if (state.isSelecting) {
                state.isSelecting = false;
            }
        });

        // 滚轮缩放
        canvas.addEventListener('wheel', (e) => {
            e.preventDefault();

            const mouseX = e.clientX;
            const mouseY = e.clientY;
            const worldPos = screenToWorld(mouseX, mouseY);
            const worldX = worldPos.x;
            const worldY = worldPos.y;

            const delta = -e.deltaY;
            const zoomFactor = delta > 0 ? 1.1 : 0.9;

            state.scale *= zoomFactor;
            state.scale = Math.max(0.1, Math.min(10, state.scale));

            state.offsetX = mouseX - worldX * state.scale;
            state.offsetY = mouseY - (-worldY) * state.scale;

            updateAnchors();
            draw();
        });

        // 切换模式函数
        function setMode(newMode) {
            selectModeBtn.classList.remove('active');
            drawModeBtn.classList.remove('active');
            rectModeBtn.classList.remove('active');
            circleModeBtn.classList.remove('active');

            state.mode = newMode;
            state.isDragging = false;
            state.isDrawing = false;
            state.isSelecting = false;
            state.isMovingShape = false;
            state.isResizing = false;

            switch (newMode) {
                case 'select':
                    selectModeBtn.classList.add('active');
                    canvas.style.cursor = 'default';
                    break;
                case 'draw':
                    drawModeBtn.classList.add('active');
                    canvas.style.cursor = 'crosshair';
                    break;
                case 'rect':
                    rectModeBtn.classList.add('active');
                    canvas.style.cursor = 'crosshair';
                    break;
                case 'circle':
                    circleModeBtn.classList.add('active');
                    canvas.style.cursor = 'crosshair';
                    break;
            }
        }

        // 颜色和线宽变化处理
        strokeColorInput.addEventListener('input', (e) => {
            state.strokeColor = e.target.value;
        });

        strokeWidthInput.addEventListener('input', (e) => {
            state.strokeWidth = parseInt(e.target.value);
        });

        // 按钮事件
        selectModeBtn.addEventListener('click', () => setMode('select'));
        drawModeBtn.addEventListener('click', () => setMode('draw'));
        rectModeBtn.addEventListener('click', () => setMode('rect'));
        circleModeBtn.addEventListener('click', () => setMode('circle'));

        // 回到原点
        resetViewBtn.addEventListener('click', () => {
            state.offsetX = canvas.width / 2;
            state.offsetY = canvas.height / 2;
            state.scale = 1;
            updateAnchors();
            draw();
        });

        // 清空画布
        clearCanvasBtn.addEventListener('click', () => {
            state.shapes = [];
            state.selectedShape = null;
            clearAnchors();
            updatePropertyPanel();
            draw();
        });

        // 初始化
        window.addEventListener('resize', resizeCanvas);
        resizeCanvas();
        setMode('select');
        updatePropertyPanel();

        // 使updateShapeProperty函数全局可用
        window.updateShapeProperty = updateShapeProperty;
    </script>